home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / DCLAP 6d / dclap6d / SeqPups / appsrc / drawtree.src / drawgram.c next >
Text File  |  1996-07-05  |  26KB  |  1,020 lines

  1.  
  2. #include "drawgraphics.h"
  3.  
  4. /* Version 3.52c.  Copyright (c) 1986-1993 by Joseph Felsenstein and
  5.   Christopher A. Meacham.  Additional code written by Hisashi Horino,
  6.   Sean Lamont, Andrew Keefe, and Akiko Fuseki.
  7.   Permission is granted to copy, distribute, and modify this
  8.   program provided that (1) this copyright message is not removed
  9.   and (2) no fee is charged for this program. */
  10.  
  11. FILE *treefile,  *plotfile;
  12. char pltfilename[100];
  13. long     ntips, nextnode,  strpwide, strpdeep,strpdiv,
  14.         strptop, strpbottom, payge, numlines;
  15. boolean  preview, previewing, dotmatrix,
  16.          haslengths, uselengths, empty, rescaled;
  17. double xmargin, ymargin, topoflabels, rightoflabels, leftoflabels,
  18.        tipspacing,maxheight, scale, xscale, yscale, xoffset, yoffset,
  19.        nodespace, stemlength, treedepth, xnow, ynow, xunitspercm, yunitspercm,
  20.        xsize, ysize, xcorner, ycorner, labelheight,labelrotation,expand, rooty,
  21.        bscale;
  22.        striptype stripe;
  23.        plottertype plotter, oldplotter, previewer;
  24.        growth grows;
  25.        treestyle style;
  26.        node *root;
  27. node *nodep[maxnodes];
  28.        fonttype font;
  29.        long filesize;
  30. Char   ch;
  31. char   fontname[64];
  32.  
  33.        enum {  yes, no} penchange,oldpenchange;
  34. static enum {  weighted, intermediate, centered, inner, vshaped} nodeposition;
  35.  
  36.  
  37. openfile(fp,filename,mode,application,perm)
  38. FILE **fp;
  39. char *filename;
  40. char *mode;
  41. char *application;
  42. char *perm;
  43. {
  44.   FILE *of;
  45.   char file[100];
  46.   strcpy(file,filename);
  47.   while (1){
  48.     of = fopen(file,mode);
  49.     if (of)
  50.       break;
  51.     else {
  52.       switch (*mode){
  53.       case 'r':
  54.     printf("%s:  can't read %s\n",application,file);
  55.     file[0] = '\0';
  56.     while (file[0] =='\0'){
  57.       printf("Please enter a new filename>");
  58.       gets(file);}
  59.     break;
  60.       case 'w':
  61.     printf("%s: can't write %s\n",application,file);
  62.     file[0] = '\0';
  63.     while (file[0] =='\0'){
  64.       printf("Please enter a new filename>");
  65.       gets(file);}
  66.     break;
  67.       }
  68.     }
  69.   }
  70.   *fp=of;
  71.   if (perm != NULL)
  72.     strcpy(perm,file);
  73. }
  74.  
  75. void uppercase(ch)
  76. Char *ch;
  77. {  /* make ch upper-case */
  78.    *ch = (islower(*ch) ?  toupper(*ch) : (*ch));
  79. }  /* uppercase */
  80.  
  81. void getch(c)
  82. Char *c;
  83. {  /* get next nonblank character */
  84.   do {
  85.     *c=getc(treefile); }
  86.   while ((*c == ' ')||(*c == '\n')||(*c == '\t'));
  87.   }  /* getch */
  88.  
  89. Void processlength(p)
  90. node *p;
  91. {
  92.   long  digit, ordzero;
  93.   double valyew, divisor;
  94.   boolean pointread, minusread;
  95.  
  96.   ordzero = '0';
  97.   pointread = false;
  98.   minusread = false;
  99.   valyew = 0.0;
  100.   divisor = 1.0;
  101.   getch(&ch);
  102.   digit = ch - ordzero;
  103.   while (((unsigned long)digit <= 9) | (ch == '.') || (ch == '-')){
  104.         if (ch == '.')   pointread = true;
  105.    else if (ch == '-')   minusread = true;
  106.    else {
  107.     valyew = valyew * 10.0 + digit;
  108.     if (pointread)
  109.       divisor *= 10.0;
  110.       }
  111.     getch(&ch);
  112.     digit = ch - ordzero;
  113.       }
  114.  if (!minusread)
  115.  p->oldlen = valyew / divisor;
  116.  else
  117.  p->oldlen = 0.0;
  118.   /* processlength */
  119. }
  120.  
  121. void addelement(p, q)
  122. node **p, *q;
  123. {
  124.   /* read in and add next part of tree, it will be node p
  125.      and will be hooked to pointer q */
  126.   node *pfirst;
  127.   long n;
  128.   boolean notlast;
  129.  
  130.   nextnode++;
  131.   *p = (node *)Malloc((long)sizeof(node));
  132.   nodep[nextnode - 1] = *p;
  133.   if (ch == '(') {
  134.     (*p)->tip = false;
  135.     (*p)->tipsabove = 0;
  136.     pfirst = *p;
  137.     notlast = true;
  138.     while (notlast) {
  139.       (*p)->next = (node *)Malloc((long)sizeof(node));
  140.       *p = (*p)->next;
  141.       (*p)->tip = false;
  142.       getch(&ch);
  143.       addelement(&(*p)->back, *p);
  144.       pfirst->tipsabove += (*p)->back->tipsabove;
  145.       if (ch == ')') {
  146.         notlast = false;
  147.         do {
  148.           getch(&ch);
  149.         } while (ch != ':' && ch != ',' && ch != ')' && ch != '[' && ch != ';');
  150.       }
  151.     }
  152.     (*p)->next = pfirst;
  153.     *p = pfirst;
  154.   } else {
  155.     (*p)->tip = true;
  156.     (*p)->tipsabove = 1;
  157.     ntips++;
  158.     n = 1;
  159.     do {
  160.       if (ch == '_')
  161.         ch = ' ';
  162.       if (!ebcdic && (ch & 255) == 255)
  163.         ch = '\'';
  164.       if (!ebcdic && (ch & 255) > 175)
  165.         ch -= 48;
  166.       if (!ebcdic && (ch & (~127)) != 0)
  167.         ch -= 64;
  168.       if (n < maxnch)
  169.         (*p)->nayme[n - 1] = ch;
  170.       if (eoln(treefile)) {
  171.         fscanf(treefile, "%*[^\n]");
  172.         getc(treefile);
  173.       }
  174.       ch = getc(treefile);
  175.       n++;
  176.     } while (ch != ':' && ch != ',' && ch != ')');
  177.     if (n > maxnch)
  178.       n = maxnch + 1;
  179.     (*p)->naymlength = n - 1;
  180.   }
  181.   if (ch == ':')
  182.     processlength(*p);
  183.   else
  184.     haslengths = (haslengths && q == NULL);
  185.   (*p)->back = q;
  186. }  /* addelement */
  187.  
  188.  
  189. void treeread()
  190. {
  191.   /* read a tree from the treefile and set up nodes and pointers */
  192.   haslengths = true;
  193.   ntips = 0;
  194.   nextnode = 0;
  195.   getch(&ch);
  196.   addelement(&root, NULL);
  197.   fscanf(treefile, "%*[^\n]");
  198.   getc(treefile);
  199.   uselengths = haslengths;
  200. }  /* treeread */
  201.  
  202.  
  203.  
  204. void initialparms()
  205. {
  206.   /* initialize parameters */
  207.   getplotter();
  208.   plotrparms();
  209.   if (dotmatrix)
  210.     numlines = (long)floor(yunitspercm * ysize + 0.5) / strpdeep;
  211.   xmargin = 0.08 * xsize;
  212.   ymargin = 0.08 * ysize;
  213.   xscale = xunitspercm;
  214.   yscale = yunitspercm;
  215.   style =  cladogram;
  216.   grows = vertical;
  217.   labelrotation = 45.0;
  218.   nodespace = 3.0;
  219.   stemlength = 0.05;
  220.   treedepth = 0.5 / 0.95;
  221.   rescaled = true;
  222.   bscale = 1.0;
  223.   if (uselengths)
  224.     nodeposition = intermediate;
  225.   else
  226.     nodeposition = vshaped;
  227. }  /* initialparms */
  228.  
  229.  
  230. long showparms()
  231. {
  232.   long i;
  233.   long numtochange;
  234.   char input[32];
  235.   Char ch, ch2,trash;
  236.  
  237.   putchar('\n');
  238.   if (previewer == tek)
  239.     printf("%c\f", escape);
  240.   else {
  241.     for (i = 1; i <= 24; i++)
  242.       putchar('\n');
  243.   }
  244.   printf("Here are the settings: \n\n");
  245.   printf(" (1)               Tree grows:  ");
  246.   printf((grows == vertical) ? "Vertically\n" : "Horizontally\n");
  247.   printf(" (2)            Style of tree:  %s\n",
  248.      (style == cladogram) ? "Cladogram" :
  249.          (style == phenogram)  ? "Phenogram" :
  250.          (style == curvogram) ? "Curvogram" :
  251.          (style == eurogram)  ? "Eurogram"  : "Swoopogram");
  252.  
  253.  
  254.   printf(" (3)       Use branch lengths:  ");
  255.   if (haslengths) {
  256.     if (uselengths)
  257.       printf("Yes\n");
  258.     else
  259.       printf("No\n");
  260.   } else
  261.     printf("(no branch lengths available)\n");
  262.   printf(" (4)          Angle of labels:");
  263.   if (labelrotation < 10.0)
  264.     printf("%5.1f\n", labelrotation);
  265.   else
  266.     printf("%6.1f\n", labelrotation);
  267.   if (plotter == ray) {
  268.     printf(" (5)       Horizontal margins:%6.2f pixels\n", xmargin);
  269.     printf(" (5)         Vertical margins:%6.2f pixels\n", ymargin);
  270.   } else {
  271.     printf(" (5)       Horizontal margins:%6.2f cm\n", xmargin);
  272.     printf(" (5)         Vertical margins:%6.2f cm\n", ymargin);
  273.   }
  274.   printf(" (6)   Scale of branch length:");
  275.   if (rescaled)
  276.     printf("  Automatically rescaled\n");
  277.   else
  278.     printf("  Fixed:%6.2f cm per unit branch length\n", bscale);
  279.   printf(" (7)    Depth/Breadth of tree:%6.2f\n", treedepth);
  280.   printf(" (8)   Stem-length/tree-depth:%6.2f\n", stemlength);
  281.   printf(" (9) Character ht / tip space:%8.4f\n", 1.0 / nodespace);
  282.   printf("(10)          Ancestral nodes:  %s\n",
  283.      (nodeposition == weighted)     ? "Weighted"     :
  284.      (nodeposition == intermediate) ? "Intermediate" :
  285.      (nodeposition == centered)     ? "Centered"     :
  286.      (nodeposition == inner)        ? "Inner"        :
  287.      "So tree is V-shaped");
  288.   if (plotter == lw)
  289.     printf("(11)          Font           :  %s\n",fontname);
  290.  
  291.   printf("\n Do you want to accept these? (Yes or No)\n");
  292.   for (;;) {
  293.     printf(" Type Y or N or the number (1-%2ld) of the one to change:\n",
  294.            ((plotter == lw) ? 11L : 10L));
  295.     gets(input);
  296.     uppercase(&input[0]);
  297.     numtochange = atoi(input);
  298.     ch = input[0];
  299.     if ((ch == 'Y' || ch == 'N') || (numtochange >= 1 && numtochange <= 11))
  300.       break;
  301.   }
  302.  return (ch == 'Y') ? -1 : numtochange;
  303. }  /* showparms */
  304.  
  305.  
  306. void getparms(numtochange)
  307. long numtochange;
  308. {
  309.   /* get from user the relevant parameters for the plotter and diagram */
  310.   Char ch,trash;
  311.   boolean ok;
  312.  
  313.   if (numtochange == 0) {
  314.     do {
  315.       printf(" Type the number of one that you want to change (1-%2ld):\n",
  316.              ((plotter == lw) ? 11L : 10L));
  317.       scanf("%hd%*[^\n]", &numtochange);
  318.       trash=getchar();
  319.     } while (numtochange < 1 || numtochange > ((plotter == lw) ? 11 : 10));
  320.   }
  321.   switch (numtochange) {
  322.  
  323.   case 1:
  324.     if (grows == vertical)
  325.       grows = horizontal;
  326.     else
  327.       grows = vertical;
  328.     break;
  329.  
  330.   case 2:
  331.     printf("\nWhat style tree is this to be:\n");
  332.     printf("   Cladogram, Phenogram, curVogram, Eurogram,");
  333.     printf("  or Swoopogram\n");
  334.     printf(" (C, P, V, E, or S)\n");
  335.     do {
  336.       printf(" Choose one: \n");
  337.       scanf("%c%*[^\n]", &ch);
  338.       trash=getchar();
  339.       uppercase(&ch);
  340.     } while (ch != 'C' && ch != 'P' && ch != 'V' && ch != 'E' && ch != 'S');
  341.     switch (ch) {
  342.  
  343.     case 'C':
  344.       style = cladogram;
  345.       break;
  346.  
  347.     case 'P':
  348.       style = phenogram;
  349.       break;
  350.  
  351.     case 'E':
  352.       style = eurogram;
  353.       break;
  354.  
  355.     case 'S':
  356.       style = swoopogram;
  357.       break;
  358.  
  359.     case 'V':
  360.       style = curvogram;
  361.       break;
  362.     }
  363.     break;
  364.  
  365.   case 3:
  366.     if (haslengths) {
  367.       uselengths = !uselengths;
  368.       if (!uselengths)
  369.         nodeposition = vshaped;
  370.       else
  371.         nodeposition = intermediate;
  372.     } else {
  373.       printf("Cannot use lengths since not all of them exist\n");
  374.       uselengths = false;
  375.     }
  376.     break;
  377.  
  378.   case 4:
  379.     printf("\n(Considering the tree as if it \"grew\" vertically:)\n");
  380.     printf("Are the labels to be plotted vertically (90),\n");
  381.     printf(" horizontally (0), or at a 45-degree angle?\n");
  382.     do {
  383.       printf(" Choose an angle in degrees from 90 to 0:\n");
  384.       scanf("%lf%*[^\n]", &labelrotation);
  385.       trash=getchar();
  386.       uppercase(&ch);
  387.     } while (labelrotation < 0.0 && labelrotation > 90.0);
  388.     break;
  389.  
  390.   case 5:
  391.     printf("\nThe tree will be drawn to fit in a rectangle which has \n");
  392.     printf(" margins in the horizontal and vertical directions of:\n");
  393.     if (plotter == ray)
  394.       printf("%6.2f pixels (horizontal margin) and%6.2f pixels (vertical margin)\n",
  395.              xmargin, ymargin);
  396.     else
  397.       printf("%6.2f cm (horizontal margin) and%6.2f cm (vertical margin)\n",
  398.              xmargin, ymargin);
  399.     putchar('\n');
  400.     do {
  401.       if (plotter == ray)
  402.         printf(" New value (in pixels) of horizontal margin?\n");
  403.       else
  404.         printf(" New value (in cm) of horizontal margin?\n");
  405.       scanf("%lf%*[^\n]", &xmargin);
  406.       trash=getchar();
  407.       ok = ((unsigned)xmargin < xsize / 2.0);
  408.       if (!ok)
  409.         printf(" Impossible value.  Please retype it.\n");
  410.     } while (!ok);
  411.     do {
  412.       if (plotter == ray)
  413.         printf(" New value (in pixels) of vertical margin?\n");
  414.       else
  415.         printf(" New value (in cm) of vertical margin?\n");
  416.       scanf("%lf%*[^\n]", &ymargin);
  417.       trash=getchar();
  418.       ok = ((unsigned)ymargin < ysize / 2.0);
  419.       if (!ok)
  420.         printf(" Impossible value.  Please retype it.\n");
  421.     } while (!ok);
  422.     break;
  423.  
  424.   case 6:
  425.     rescaled = !rescaled;
  426.     if (!rescaled) {
  427.       printf("Centimeters per unit branch length?\n");
  428.       scanf("%lf%*[^\n]", &bscale);
  429.       trash=getchar();
  430.     }
  431.     break;
  432.  
  433.   case 7:
  434.     printf("New value of depth of tree as fraction of its breadth?\n");
  435.     scanf("%lf%*[^\n]", &treedepth);
  436.     trash=getchar();
  437.     break;
  438.  
  439.   case 8:
  440.     do {
  441.       printf("New value of stem length as fraction of tree depth?\n");
  442.       scanf("%lf%*[^\n]", &stemlength);
  443.       trash=getchar();
  444.     } while ((unsigned)stemlength >= 0.9);
  445.     break;
  446.  
  447.   case 9:
  448.     printf("New value of character height as fraction of tip spacing?\n");
  449.     scanf("%lf%*[^\n]", &nodespace);
  450.     trash=getchar();
  451.     nodespace = 1.0 / nodespace;
  452.     break;
  453.  
  454.   case 10:
  455.     printf("Should interior node positions:\n");
  456.     printf(" be Intermediate between their immediate descendants,\n");
  457.     printf("    Weighted average of tip positions\n");
  458.     printf("    Centered among their ultimate descendants\n");
  459.     printf("    iNnermost of immediate descendants\n");
  460.     printf(" or so that tree is V-shaped\n");
  461.     do {
  462.       printf(" (type I, W, C, N or V):\n");
  463.       scanf("%c%*[^\n]", &ch);
  464.       trash=getchar();
  465.       uppercase(&ch);
  466.     } while (ch != 'I' && ch != 'W' && ch != 'C' && ch != 'N' && ch != 'V');
  467.     switch (ch) {
  468.  
  469.     case 'W':
  470.       nodeposition = weighted;
  471.       break;
  472.  
  473.     case 'I':
  474.       nodeposition = intermediate;
  475.       break;
  476.  
  477.     case 'C':
  478.       nodeposition = centered;
  479.       break;
  480.  
  481.     case 'N':
  482.       nodeposition = inner;
  483.       break;
  484.  
  485.     case 'V':
  486.       nodeposition = vshaped;
  487.       break;
  488.     }
  489.     break;
  490.   case 11:
  491.     printf("Enter font name or \"Hershey\" for the default font\n");
  492.     gets(fontname);
  493.     break;
  494.   }
  495. }  /* getparms */
  496.  
  497.  
  498.  
  499. void calctraverse(p, lengthsum,tipx)
  500. node *p;
  501. double lengthsum;
  502. double *tipx;
  503. {
  504.   /* traverse to establish initial node coordinates */
  505.   double x1, y1, x2, y2, x3, w1, w2, sumwx, sumw, nodeheight, rr;
  506.   node *pp, *plast;
  507.  
  508.   if (p == root)
  509.     nodeheight = 0.0;
  510.   else if (uselengths)
  511.     nodeheight = lengthsum + p->oldlen;
  512.   else
  513.     nodeheight = 1.0;
  514.   if (nodeheight > maxheight)
  515.     maxheight = nodeheight;
  516.   if (p->tip) {
  517.     p->xcoord = *tipx;
  518.     if (uselengths)
  519.       p->ycoord = nodeheight;
  520.     else
  521.       p->ycoord = 1.0;
  522.     *tipx += tipspacing;
  523.     return;
  524.   }
  525.   sumwx = 0.0;
  526.   sumw = 0.0;
  527.   pp = p->next;
  528.   x3 = 0.0;
  529.   do {
  530.     calctraverse(pp->back, nodeheight,tipx);
  531.     sumw += pp->back->tipsabove;
  532.     sumwx += pp->back->tipsabove * pp->back->xcoord;
  533.     if (fabs(pp->back->xcoord - 0.5) < fabs(x3 - 0.5))
  534.       x3 = pp->back->xcoord;
  535.     plast = pp;
  536.     pp = pp->next;
  537.   } while (pp != p);
  538.   x1 = p->next->back->xcoord;
  539.   x2 = plast->back->xcoord;
  540.   y1 = p->next->back->ycoord;
  541.   y2 = plast->back->ycoord;
  542.   rr = 2 * (1.0 - stemlength) * treedepth * maxheight;
  543.   switch (nodeposition) {
  544.  
  545.   case weighted:
  546.     w1 = y1 - nodeheight;
  547.     w2 = y2 - nodeheight;
  548.     if (w1 + w2 <= 0.0)
  549.       p->xcoord = (x1 + x2) / 2.0;
  550.     else
  551.       p->xcoord = (w2 * x1 + w1 * x2) / (w1 + w2);
  552.     break;
  553.  
  554.   case intermediate:
  555.     p->xcoord = (x1 + x2) / 2.0;
  556.     break;
  557.  
  558.   case centered:
  559.     p->xcoord = sumwx / sumw;
  560.     break;
  561.  
  562.   case inner:
  563.     p->xcoord = x3;
  564.     break;
  565.  
  566.   case vshaped:
  567.     p->xcoord = (x1 + x2 + (y1 - y2) / rr) / 2.0;
  568.     break;
  569.   }
  570.   if (uselengths) {
  571.     p->ycoord = nodeheight;
  572.     return;
  573.   }
  574.   if (nodeposition != inner) {
  575.     p->ycoord = (y1 + y2 - sqrt((y1 + y2) * (y1 + y2) - 4 * (y1 * y2 -
  576.                  rr * rr * (x2 - p->xcoord) * (p->xcoord - x1)))) / 2.0;
  577.  
  578.     return;
  579.   }
  580.   if (fabs(x1 - 0.5) > fabs(x2 - 0.5)) {
  581.     p->ycoord = y1 + x1 - x2;
  582.     w1 = y2 - p->ycoord;
  583.   } else {
  584.     p->ycoord = y2 + x1 - x2;
  585.     w1 = y1 - p->ycoord;
  586.   }
  587.   if (w1 < epsilon)
  588.     p->ycoord -= fabs(x1 - x2);
  589. }  /* calctraverse */
  590.  
  591.  
  592. void calculate()
  593. {
  594.   /* compute coordinates for tree */
  595.   double tipx;
  596.   double sum, maxtextlength, textlength, firstlet, fontheight, angle;
  597.   long i;
  598.   for (i = 0; i < nextnode; i++)
  599.     nodep[i]->xcoord = 0.0;
  600.   for (i = 0; i < nextnode; i++)
  601.     nodep[i]->ycoord = 0.0;
  602.   maxheight = 0.0;
  603.   maxtextlength = 0.0;
  604.   if (nodep[0]->naymlength > 0)
  605.     firstlet = lengthtext(nodep[0]->nayme, 1L,font);
  606.   else
  607.     firstlet = 0.0;
  608.   sum = 0.0;
  609.   tipx = 0.0;
  610.     for (i = 0; i < nextnode; i++) {
  611.     if (nodep[i]->tip) {
  612.       textlength = lengthtext(nodep[i]->nayme, nodep[i]->naymlength,font);
  613.       if (textlength > maxtextlength)
  614.         maxtextlength = textlength;
  615.     }
  616.   }
  617.   fontheight = font[2];
  618.   angle = pi * labelrotation / 180.0;
  619.   maxtextlength /= fontheight;
  620.   textlength /= fontheight;
  621.   firstlet /= fontheight;
  622.   if (ntips > 1)
  623.     labelheight = 1.0 / (nodespace * (ntips - 1));
  624.   else
  625.     labelheight = 1.0 / nodespace;
  626.   if (angle < pi / 6.0)
  627.     tipspacing = (nodespace + cos(angle) * (maxtextlength - 0.5)) * labelheight;
  628.   else if (ntips > 1)
  629.     tipspacing = 1.0 / (ntips - 1.0);
  630.   else
  631.     tipspacing = 1.0;
  632.   topoflabels = labelheight *
  633.                 (1.0 + sin(angle) * (maxtextlength - 0.5) + cos(angle) * 0.5);
  634.   rightoflabels = labelheight *
  635.                   (cos(angle) * (textlength - 0.5) + sin(angle) * 0.5);
  636.   leftoflabels = labelheight * (cos(angle) * firstlet * 0.5 + sin(angle) * 0.5);
  637.   calctraverse(root, sum, &tipx);
  638.   rooty = root->ycoord;
  639.   for (i = 0; i < nextnode; i++) {
  640.     if (rescaled) {
  641.       nodep[i]->xcoord *= 1.0 - stemlength;
  642.       nodep[i]->ycoord = stemlength * treedepth + (1.0 - stemlength) *
  643.             treedepth * (nodep[i]->ycoord - rooty) / (maxheight - rooty);
  644.     } else {
  645.       nodep[i]->xcoord = nodep[i]->xcoord * (maxheight - rooty) / treedepth;
  646.       nodep[i]->ycoord = stemlength / (1 - stemlength) * (maxheight - rooty) +
  647.                          nodep[i]->ycoord;
  648.     }
  649.   }
  650.   rooty = 0.0;
  651. }  /* calculate */
  652.  
  653.  
  654. void rescale()
  655. {
  656.   /* compute coordinates of tree for plot or preview device */
  657.   long i;
  658.   double treeheight, treewidth, extrax, extray, temp;
  659.  
  660.   treeheight = 0.0;
  661.   for (i = 0; i < nextnode; i++) {
  662.     if (nodep[i]->ycoord > treeheight)
  663.       treeheight = nodep[i]->ycoord;
  664.   }
  665.   treewidth = (ntips - 1) * tipspacing + rightoflabels + leftoflabels;
  666.   if (rescaled) {
  667.     leftoflabels *= 1.0 - stemlength;
  668.     rightoflabels *= 1.0 - stemlength;
  669.     treewidth *= 1.0 - stemlength;
  670.   } else {
  671.     if (uselengths) {
  672.       labelheight = labelheight * (maxheight - rooty) / treedepth;
  673.       topoflabels = topoflabels * (maxheight - rooty) / treedepth;
  674.       leftoflabels = leftoflabels * (maxheight - rooty) / treedepth;
  675.       rightoflabels = rightoflabels * (maxheight - rooty) / treedepth;
  676.       treewidth = treewidth * (maxheight - rooty) / treedepth;
  677.     }
  678.   }
  679.   treeheight += topoflabels;
  680.   if (grows == vertical) {
  681.     if (!rescaled)
  682.       expand = bscale;
  683.     else {
  684.       expand = (xsize - 2 * xmargin) / treewidth;
  685.       if ((ysize - 2 * ymargin) / treeheight < expand)
  686.         expand = (ysize - 2 * ymargin) / treeheight;
  687.     }
  688.     extrax = (xsize - 2 * xmargin - treewidth * expand) / 2.0;
  689.     extray = (ysize - 2 * ymargin - treeheight * expand) / 2.0;
  690.   } else {
  691.     if (!rescaled)
  692.       expand = bscale;
  693.     else {
  694.       expand = (ysize - 2 * ymargin) / treewidth;
  695.       if ((xsize - 2 * xmargin) / treeheight < expand)
  696.         expand = (xsize - 2 * xmargin) / treeheight;
  697.     }
  698.     extrax = (xsize - 2 * xmargin - treeheight * expand) / 2.0;
  699.     extray = (ysize - 2 * ymargin - treewidth * expand) / 2.0;
  700.   }
  701.   for (i = 0; i < nextnode; i++) {
  702.     nodep[i]->xcoord = expand * (nodep[i]->xcoord + leftoflabels);
  703.     nodep[i]->ycoord = expand * (nodep[i]->ycoord - rooty);
  704.     if (grows == horizontal) {
  705.       temp = nodep[i]->ycoord;
  706.       nodep[i]->ycoord = expand * treewidth - nodep[i]->xcoord;
  707.       nodep[i]->xcoord = temp;
  708.     }
  709.     nodep[i]->xcoord += xmargin + extrax;
  710.     nodep[i]->ycoord += ymargin + extray;
  711.   }
  712.   if (grows == vertical)
  713.     rooty = ymargin + extray;
  714.   else
  715.     rooty = xmargin + extrax;
  716. }  /* rescale */
  717.  
  718.  
  719.  
  720. void plottree(p, q)
  721. node *p, *q;
  722. {
  723.   /* plot part or all of tree on the plotting device */
  724.   long i;
  725.   double x1, y1, x2, y2, x3, y3, f, g, h, fract, minny, miny;
  726.   node *pp;
  727.  
  728.   x2 = xscale * (xoffset + p->xcoord);
  729.   y2 = yscale * (yoffset + p->ycoord);
  730.   if (p != root) {
  731.     x1 = xscale * (xoffset + q->xcoord);
  732.     y1 = yscale * (yoffset + q->ycoord);
  733.     plot(penup, x1, y1);
  734.     switch (style) {
  735.  
  736.     case cladogram:
  737.       plot(pendown, x2, y2);
  738.       break;
  739.  
  740.     case phenogram:
  741.       if (grows == vertical)
  742.         plot(pendown, x2, y1);
  743.       else
  744.         plot(pendown, x1, y2);
  745.       plot(pendown, x2, y2);
  746.       break;
  747.  
  748.     case curvogram:
  749.       for (i = 1; i <= segments; i++) {
  750.         f = (double)i / segments;
  751.         g = (double)i / segments;
  752.         h = 1.0 - sqrt(1.0 - g * g);
  753.         if (grows == vertical) {
  754.           x3 = x1 * (1.0 - f) + x2 * f;
  755.           y3 = y1 + (y2 - y1) * h;
  756.         } else {
  757.           x3 = x1 + (x2 - x1) * h;
  758.           y3 = y1 * (1.0 - f) + y2 * f;
  759.         }
  760.         plot(pendown, x3, y3);
  761.       }
  762.       break;
  763.  
  764.     case eurogram:
  765.       if (grows == vertical)
  766.         plot(pendown, x2, (2 * y1 + y2) / 3);
  767.       else
  768.         plot(pendown, (2 * x1 + x2) / 3, y2);
  769.       plot(pendown, x2, y2);
  770.       break;
  771.  
  772.     case swoopogram:
  773.       if ((grows == vertical && fabs(y1 - y2) >= epsilon) ||
  774.           (grows == horizontal && fabs(x1 - x2) >= epsilon)) {
  775.         if (grows == vertical)
  776.           miny = p->ycoord;
  777.         else
  778.           miny = p->xcoord;
  779.         pp = q->next;
  780.         while (pp != q) {
  781.           if (grows == vertical)
  782.             minny = pp->back->ycoord;
  783.           else
  784.             minny = pp->back->xcoord;
  785.           if (minny < miny)
  786.             miny = minny;
  787.           pp = pp->next;
  788.         }
  789.         if (grows == vertical)
  790.           miny = yscale * (yoffset + miny);
  791.         else
  792.           miny = xscale * (xoffset + miny);
  793.         if (grows == vertical)
  794.           fract = 0.3333 * (miny - y1) / (y2 - y1);
  795.         else
  796.           fract = 0.3333 * (miny - x1) / (x2 - x1);
  797.         for (i = 1; i <= segments; i++) {
  798.           f = (double)i / segments;
  799.           if (f < fract)
  800.             g = f / fract;
  801.           else
  802.             g = (f - fract) / (1.0 - fract);
  803.           if (f < fract)
  804.             h = fract * sqrt(1.0 - (1.0 - g) * (1.0 - g));
  805.           else
  806.             h = fract + (1.0 - fract) * (1.000001 - sqrt(1.000001 - g * g));
  807.           if (grows == vertical) {
  808.             x3 = x1 * (1.0 - f) + x2 * f;
  809.             y3 = y1 + (y2 - y1) * h;
  810.           } else {
  811.             x3 = x1 + (x2 - x1) * h;
  812.             y3 = y1 * (1.0 - f) + y2 * f;
  813.           }
  814.           plot(pendown, x3, y3);
  815.         }
  816.       }
  817.       break;
  818.     }
  819.   } else {
  820.     if (grows == vertical) {
  821.       x1 = xscale * (xoffset + p->xcoord);
  822.       y1 = yscale * (yoffset + rooty);
  823.     } else {
  824.       x1 = xscale * (xoffset + rooty);
  825.       y1 = yscale * (yoffset + p->ycoord);
  826.     }
  827.     plot(penup, x1, y1);
  828.     plot(pendown, x2, y2);
  829.   }
  830.   if (p->tip)
  831.     return;
  832.   pp = p->next;
  833.   while (pp != p) {
  834.     plottree(pp->back, p);
  835.     pp = pp->next;
  836.   }
  837. }  /* plottree */
  838.  
  839.  
  840.  
  841. void plotlabels(fontname)
  842. char *fontname;
  843. {
  844.   long i;
  845.   double compr, dx, dy, angle;
  846.   node *lp;
  847.  
  848.   compr = xunitspercm / yunitspercm;
  849.   if (penchange == yes)
  850.     changepen(labelpen);
  851.   angle = labelrotation * pi / 180.0;
  852.   for (i = 0; i < (nextnode); i++) {
  853.     if (nodep[i]->tip) {
  854.       lp = nodep[i];
  855.       dx = labelheight * expand * -0.70710 * cos(angle + pi / 4.0);
  856.       dy = labelheight * expand * (1.0 - 0.70710 * sin(angle + pi / 4.0));
  857.       if (grows == vertical)
  858.         plottext(lp->nayme, lp->naymlength,
  859.                  labelheight * expand * xscale / compr, compr,
  860.                  xscale * (lp->xcoord + dx + xoffset),
  861.                  yscale * (lp->ycoord + dy + yoffset),
  862.          -labelrotation, font,fontname);
  863.       else
  864.         plottext(lp->nayme, lp->naymlength, labelheight * expand * yscale,
  865.                  compr, xscale * (lp->xcoord + dy + xoffset),
  866.                  yscale * (lp->ycoord - dx + yoffset), 90.0 - labelrotation,
  867.                  font,fontname);
  868.     }
  869.   }
  870.   if (penchange == yes)
  871.     changepen(treepen);
  872. }  /* plotlabels */
  873.  
  874.  
  875. #ifdef CHILDAPP
  876. void RealMain(int argc, char** argv)
  877. #else
  878. main(argc, argv)
  879. long argc;
  880. Char *argv[];
  881. #endif
  882. {
  883.   long i,n,stripedepth;
  884.   boolean canbeplotted;
  885.  
  886. #if defined(MAC) || defined(__MWERKS__)
  887.   OSErr retcode;
  888.   FInfo  fndrinfo;
  889. #ifdef MAC
  890.   macsetup("Drawgram","Preview");
  891. #endif
  892. #endif
  893. #ifdef TURBOC
  894.   if ((registerbgidriver(EGAVGA_driver) <0) ||
  895.       (registerbgidriver(Herc_driver) <0)   ||
  896.       (registerbgidriver(CGA_driver) <0)){
  897.     printf("Graphics error: %s ",grapherrormsg(graphresult()));
  898.     exit(-1);}
  899. #endif
  900.   strcpy(fontname,"Hershey");
  901.  
  902.   openfile(&plotfile,PLOTFILE,"w",argv[0],pltfilename);
  903.   openfile(&treefile,TREEFILE,"r",argv[0],NULL);
  904.  
  905.   printf("DRAWGRAM from PHYLIP version %s\n",VERSION);
  906.   printf("Reading tree ... \n");
  907.   treeread();
  908.  
  909.   printf("Tree has been read.\nLoading the font .... \n");
  910.   loadfont(font,argv[0]);
  911.   printf("Font loaded.\n");
  912.   previewing = false;
  913.   initialparms();
  914.   canbeplotted = false;
  915.   while (!canbeplotted) {
  916.     do {
  917.       n=showparms();
  918.       if (n  != -1)
  919.         getparms(n);
  920.     } while (n  != -1);
  921.     calculate();
  922.     rescale();
  923.     canbeplotted = true;
  924.     if (preview)
  925.       canbeplotted=plotpreview(fontname,&xoffset,&yoffset,&scale,ntips,root);
  926.   }
  927.   if (dotmatrix) {
  928.      stripedepth = allocstripe(stripe,(strpwide/8),
  929.                 ((long)(yunitspercm * ysize)));
  930.      strpdeep = stripedepth;
  931.      strpdiv  = stripedepth;
  932.      }
  933.   previewing = false;
  934.   initplotter(ntips,fontname);
  935.   numlines = dotmatrix ? ((long)floor(yunitspercm * ysize + 0.5)/strpdeep) : 1;
  936.   if (plotter != ibmpc)
  937.     printf("Writing plot file ...\n");
  938.   drawit(fontname,&xoffset,&yoffset,numlines,root);
  939.   finishplotter();
  940.   FClose(plotfile);
  941.   FClose(treefile);
  942.   printf("Finished.\nEnd of run.\n");
  943.   
  944. #if defined(__MWERKS__)
  945. if (plotter == pict){
  946.   retcode= getfinfo( PLOTFILE,0,&fndrinfo);
  947.   fndrinfo.fdType='PICT';
  948.   fndrinfo.fdCreator='MDRW';
  949.   retcode=setfinfo( PLOTFILE,0,&fndrinfo);
  950.   }
  951. if (plotter == lw){
  952.   retcode=getfinfo( PLOTFILE,0,&fndrinfo);
  953.   fndrinfo.fdType='TEXT';
  954.   retcode=setfinfo( PLOTFILE,0,&fndrinfo);
  955.   }
  956. #endif
  957. #if defined(MAC)
  958. if (plotter == pict){
  959.   retcode=GetFInfo(CtoPstr(PLOTFILE),0,&fndrinfo);
  960.   fndrinfo.fdType='PICT';
  961.   fndrinfo.fdCreator='MDRW';
  962.   retcode=SetFInfo(CtoPstr(PLOTFILE),0,&fndrinfo);}
  963. if (plotter == lw){
  964.   retcode=GetFInfo(CtoPstr(PLOTFILE),0,&fndrinfo);
  965.   fndrinfo.fdType='TEXT';
  966.   retcode=SetFInfo(CtoPstr(PLOTFILE),0,&fndrinfo);}
  967. #endif
  968.   exit(0);
  969. }
  970.  
  971.  
  972.  
  973. int eof(f)
  974. FILE *f;
  975. {
  976.     register long ch;
  977.  
  978.     if (feof(f))
  979.         return 1;
  980.     if (f == stdin)
  981.         return 0;
  982.     ch = getc(f);
  983.     if (ch == EOF)
  984.         return 1;
  985.     ungetc(ch, f);
  986.     return 0;
  987. }
  988.  
  989.  
  990. int eoln(f)
  991. FILE *f;
  992. {
  993.     register long ch;
  994.  
  995.     ch = getc(f);
  996.     if (ch == EOF)
  997.         return 1;
  998.     ungetc(ch, f);
  999.     return (ch == '\n');
  1000. }
  1001.  
  1002. void memerror()
  1003. {
  1004. printf("Error allocating memory\n");
  1005. exit(-1);
  1006. }
  1007.  
  1008. MALLOCRETURN *mymalloc(x)
  1009. long x;
  1010. {
  1011. MALLOCRETURN *mem;
  1012. mem = (MALLOCRETURN *)malloc((size_t)x);
  1013. if (!mem)
  1014.      memerror();
  1015. else
  1016.      return (MALLOCRETURN *)mem;
  1017.  
  1018. }
  1019.  
  1020.